using System.ComponentModel;
using Castle.DynamicProxy;

namespace EntityAop.Interceptors.Support
{
    public static class NotificationHelper
    {
        public static void NotifyDependent(IInvocation invocation, string notifierName, PropertyChangedEventHandler handler)
        {
            if (handler == null)
            {
                return;
            }

            EntityMetadata currentEntityMetadata = EntityMetadataHelper.GetEntityMetadata(invocation);

            if (currentEntityMetadata == null)
            {
                return;
            }

            var dependencies = currentEntityMetadata.GetDependencies(notifierName);

            if (dependencies == null)
            {
                return;
            }

            foreach (var dependency in dependencies)
            {
                if (dependency.IsAnotherInstanceDependent)
                {
                    NotifyInverseReference(invocation, dependency);

                    continue;
                }

                NotifyDependent(invocation, dependency.Value, handler);

                handler(invocation.Proxy, new PropertyChangedEventArgs(dependency.Value));
            }
        }

        public static void ProceedSetterNotifications(IInvocation invocation, string propertyName)
        {
            var propertyChangedEventHandler = InstanceSpecificHelper.GetInstanceSpecificData(invocation).PropertyChangedEventHandler;

            if (propertyChangedEventHandler == null)
            {
                return;
            }

            propertyChangedEventHandler(invocation.Proxy,
                                        new PropertyChangedEventArgs(propertyName));

            NotifyDependent(invocation, propertyName, propertyChangedEventHandler);
        }

        private static void NotifyInverseReference(IInvocation invocation, EntityMetadata.Element.ElementValue dependency)
        {
            var splitted = dependency.Value.Split('|');
            var dependentValue = new
                                     {
                                         Type = splitted[0],
                                         Property = splitted[1]
                                     };

            foreach (var inverseReference
                in InstanceSpecificHelper.GetInstanceSpecificData(invocation).GetRegisteredInverseReferences(dependentValue.Type))
            {
                InstanceSpecificHelper.GetInstanceSpecificData(inverseReference)
                    .PropertyChangedEventHandler(invocation.Proxy, new PropertyChangedEventArgs(dependentValue.Property));
            }
        }
    }
}